import alea from "alea";
import { createNoise2D } from "simplex-noise";
import { areas, areasAllWeight } from "@/assets/area.js";
import { isEmpty } from "@/util/common.js";
import { getBlockById } from "@/util/block.js";
import { getBasicBlocksWeight } from "@/util/area.js";

const SEEDMIN = 0;
const SEEDMAX = 10000;

/**
 * 获取一个方块的数据
 * @param {*} x 世界坐标x
 * @param {*} y 世界坐标y
 * @param {*} worldSeed 世界种子
 * @param {*} scale 频率缩放(值越小,变化幅度越小)
 * @returns 方块对象
 */
export const getBlock = (x, y, worldSeed, scale) => {
  const noise = createNoise2D(alea(worldSeed));
  let num =
    ((noise(x * scale, y * scale) + 1) / 2) * (SEEDMAX - SEEDMIN) + SEEDMIN;

  // 随机区域
  let area = getAreaByNum(num);

  // 随机一个概率方块
  let probabilityBlockId = getProbabilityBlock(
    area.probabilityBlocks,
    worldSeed,
    x,
    y,
    area.probabilityBlockAmplitude
  );

  if (!isEmpty(probabilityBlockId)) {
    // 如果随机到概率方块了，就用他
    return getBlockById(probabilityBlockId);
  } else {
    // 使用基本方块
    return getBasicBlock(
      area.basicBlocks,
      worldSeed,
      x,
      y,
      area.basicBlockAmplitude
    );
  }
};

/**
 * 根据比较数获取一个区域
 * @param {*} num 比较数
 * @returns 区域对象
 */
function getAreaByNum(num) {
  let areasList = areas.sort((a, b) => a.generateWeight - b.generateWeight);
  let maxSeed = SEEDMIN; // 累计执行过的比较值

  return areasList.find((area) => {
    let percent = area.generateWeight / areasAllWeight;
    let compareSeed = (SEEDMAX - SEEDMIN) * percent + maxSeed;
    maxSeed = compareSeed;
    return num <= compareSeed;
  });
}

/**
 * 随机选择一个概率方块, 没有随机到就返回null
 * @param {*} probabilityBlocks 概率方块列表
 * @param {*} worldSeed 世界种子
 * @param {*} x 世界坐标x
 * @param {*} y 世界坐标y
 * @param {*} amplitude 振幅
 * @returns 方块对象 或 null
 */
function getProbabilityBlock(probabilityBlocks, worldSeed, x, y, amplitude) {
  let block = probabilityBlocks.find((block) => {
    let num = getNoise(
      x,
      y,
      worldSeed + `probabilityBlock:${worldSeed}:${block.id}`,
      amplitude
    );
    let compareNum = (SEEDMAX - SEEDMIN) * block.odds;
    return compareNum > num;
  });
  if (!isEmpty(block)) {
    return block.id;
  } else {
    return null;
  }
}

/**
 * 随机选择一个基本方块
 * @param {*} basicBlocks 基本方块列表
 * @param {*} worldSeed 世界种子
 * @param {*} x 世界坐标x
 * @param {*} y 世界坐标y
 * @param {*} amplitude 振幅
 * @returns 方块对象
 */
function getBasicBlock(basicBlocks, worldSeed, x, y, amplitude) {
  let num = getNoise(x, y, `basicBlock:${worldSeed}`, amplitude);
  let blocksList = basicBlocks.sort(
    (a, b) => a.generateWeight - b.generateWeight
  );
  let maxSeed = SEEDMIN; // 累计执行过的比较值

  let allWeight = getBasicBlocksWeight(basicBlocks);

  let block = blocksList.find((block) => {
    let percent = block.generateWeight / allWeight;
    let compareSeed = (SEEDMAX - SEEDMIN) * percent + maxSeed;
    maxSeed = compareSeed;
    
    return num <= compareSeed;
  });

  return getBlockById(block.id);
}

/**
 * 获取柏林噪声映射后结果值
 * @param {*} x 世界坐标x
 * @param {*} y 世界坐标y
 * @param {*} seed 世界种子
 * @param {*} scale 频率缩放(值越小,变化幅度越小)
 * @returns 比较值
 */
function getNoise(x, y, seed, scale) {
  const noise = createNoise2D(alea(seed));
  return (
    ((noise(x * scale, y * scale) + 1) / 2) * (SEEDMAX - SEEDMIN) + SEEDMIN
  );
}
